package ift585.client;


import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class FenetreClient {
	// Taille des éléments
	private static final int TAILLE_PAQUET = 1024;
	public static final int TAILLE_TABLEAU = 20;
	private static final int TAILLE_FENETRE = 4;
	
	// Fichier représentant le fin de l'envoie
	public static final int CLOSE_ACK = TAILLE_TABLEAU +1;
	private static final byte[][] END_BYTE = null;
	
	// indicateur de position du début de la fenêtre
	private int debutFenetre = 0;
	
	// tableau de stockage
	private SendState tableEtat[] = null;
	private byte[] tablePaquet[] = null;
	
	// Classe qui gère la remplissage des fenêtres
	private FileSplitterUtility splitter;
	
	public FenetreClient(String FileName) throws IOException {
		debutFenetre = 0;
		tableEtat = new SendState[TAILLE_TABLEAU];
		tablePaquet = new byte[TAILLE_TABLEAU][TAILLE_PAQUET];
		
		// initialiser le tablePaquet avec les TaillePaquets Premier paquet 
		initFenetre(FileName);
	}
	
	private void initFenetre(String fileName) throws IOException {
		splitter = new FileSplitterUtility(fileName);
		
		for(int i = 0 ; i < tableEtat.length ; ++i){
			tableEtat[i] = SendState.notAck;
		}
		
		for(int i = 0 ; i < TAILLE_FENETRE; i++){
			tablePaquet[i] = splitter.getNextChunk(i);
		}
	}
	
	public List<byte[]> getProchainsPaquets(){ 
		List<byte[]> prochainsPaquets = new ArrayList<byte[]>();
		
		for(int i = 0 ; i < TAILLE_FENETRE-1 ; i++){
			byte[] leProchainPaquet = tablePaquet[(debutFenetre + i) % TAILLE_TABLEAU];
			
			if(leProchainPaquet == null){
				break;
			}
			
			SendState etatDuProchainPaquet = tableEtat[(debutFenetre + i) % TAILLE_TABLEAU];
			
			if(etatDuProchainPaquet == SendState.notAck){
				
				byte[] paquetAEnvoyer = tablePaquet[(debutFenetre + i) % TAILLE_TABLEAU];
				
				prochainsPaquets.add(paquetAEnvoyer);
			}
		}
		
		return prochainsPaquets;
	}

	
	public List<byte[]> getProchainsPaquets(byte[] dataReceived) throws IOException{ // Apr�s r�ception d'un ack
		
		int ackSeq = splitter.getAckNumber(dataReceived);
		
		if (ackIsValid(ackSeq)) {
			for (int i = 0; (debutFenetre + i) % TAILLE_TABLEAU != ackSeq; i++) {
				tableEtat[(debutFenetre + i) % TAILLE_TABLEAU] = SendState.ack;
			}
			while (tableEtat[debutFenetre] == SendState.ack) {
				tableEtat[(debutFenetre + TAILLE_FENETRE) % TAILLE_TABLEAU] = SendState.notAck;
				tablePaquet[(debutFenetre + TAILLE_FENETRE) % TAILLE_TABLEAU] = splitter
						.getNextChunk((debutFenetre + TAILLE_FENETRE)
								% TAILLE_TABLEAU);
				debutFenetre = (debutFenetre + 1) % TAILLE_TABLEAU;
			}
		}
		return getProchainsPaquets();
	}
	
	private boolean ackIsValid(int ackSeq){
		// Détermine la façon de voir s'il est dans la fentre car buffer circulaire
		if(debutFenetre <= (TAILLE_TABLEAU - TAILLE_FENETRE)){
			// Valide si le ack est dans la fenetre
			if(debutFenetre <= ackSeq && ackSeq <= (TAILLE_TABLEAU -1)){
				// valide si déjà reconnue
				return(tableEtat[ackSeq] != SendState.ack);
			}
		}
		else{
			// Valide si le ack est dans la fenetre
			if(!(((debutFenetre + TAILLE_FENETRE)%TAILLE_TABLEAU) < ackSeq && ackSeq < debutFenetre)){
				return(tableEtat[ackSeq] != SendState.ack);
			}
		}
		return false;
	}
}
